#include <iostream>
#include <thread>
#include <atomic>
#include <chrono>
#include <vector>
#include <random>
#include <cmath>

std::atomic<bool> channelBusy(false);
std::atomic<int> collisionCount(0);
const int MAX_NODES = 5;
const int SLOT_TIME = 10;
const int JAM_TIME = 20;
const int MAX_ATTEMPTS = 10;

void nodeBehavior(int id) {
    std::random_device rd;
    std::mt19937 gen(rd());
    std::uniform_int_distribution<> distrib(0, 100);

    int attempts = 0;
    bool transmitted = false;

    while (!transmitted && attempts < MAX_ATTEMPTS) {
        attempts++;
        bool collisionDetected = false;

        while (true) {
            if (!channelBusy.load()) {
                bool expected = false;
                if (channelBusy.compare_exchange_strong(expected, true)) {
                    break;
                }
            }
            std::this_thread::sleep_for(std::chrono::milliseconds(1));
        }

        int waitTime = distrib(gen) % 50 + 10;
        auto start = std::chrono::steady_clock::now();

        while (std::chrono::duration_cast<std::chrono::milliseconds>(
            std::chrono::steady_clock::now() - start).count() < waitTime) {
            if (collisionCount.load() > 0) {
                collisionDetected = true;
                break;
            }
            std::this_thread::sleep_for(std::chrono::milliseconds(1));
        }

        if (collisionDetected) {
            collisionCount++;
            channelBusy = false;
            std::this_thread::sleep_for(std::chrono::milliseconds(JAM_TIME));
            collisionCount--;
            int backoff = pow(2, attempts) * SLOT_TIME;
            std::this_thread::sleep_for(std::chrono::milliseconds(backoff));
        }
        else {
            if (collisionCount.load() == 0) {
                std::cout << "Node " << id << " transmitting data\n";
                std::this_thread::sleep_for(std::chrono::milliseconds(100));
                transmitted = true;
            }
            else {
                collisionDetected = true;
                collisionCount++;
                channelBusy = false;
                std::this_thread::sleep_for(std::chrono::milliseconds(JAM_TIME));
                collisionCount--;
                int backoff = pow(2, attempts) * SLOT_TIME;
                std::this_thread::sleep_for(std::chrono::milliseconds(backoff));
            }
        }
    }

    if (!transmitted) {
        std::cout << "Node " << id << " transmission failed\n";
    }
}

int main() {
    std::vector<std::thread> nodes;
    for (int i = 0; i < MAX_NODES; ++i) {
        nodes.emplace_back(nodeBehavior, i);
    }

    for (auto& node : nodes) {
        node.join();
    }

    return 0;
}